use std::{rc::Rc, cell::RefCell, sync::{Arc, Mutex, atomic::{AtomicIsize, Ordering}}, collections::HashMap};

use once_cell::sync::Lazy;

use crate::{instructions::base::Instruction, rtda::{Frame, Thread}};

// 同步指令
// 同步一段指令集序列通常是由Java语言中的synchronized语句块来表示的

// 《Java虚拟机规范》的要求，在执行monitorenter指令时，首先要去尝试获取对象的锁。如果
// 这个对象没被锁定，或者当前线程已经持有了那个对象的锁，就把锁的计数器的值增加一，而在执行
// monitorexit指令时会将锁计数器的值减一。一旦计数器的值为零，锁随即就被释放了。如果获取对象
// 锁失败，那当前线程就应当被阻塞等待，直到请求锁定的对象被持有它的线程释放为止。

// 1、如果与objectref关联的监视器的条目计数为零，则线程将进入监视器并将其条目计数设置为1。然后线程就是监视器的所有者。
// 2、如果线程已经拥有与objectref相关联的监视器，它将重新进入监视器，并递增其条目计数。
// 3、如果另一个线程已经拥有与objectref关联的监视器，则该线程会阻塞监视器，直到监视器的条目计数为零，然后再次尝试获得所有权。

// 进入同步方法 以栈定元素（即f）作为锁，开始同步
// Enter monitor for object

// 将锁对象存入此map， 用rust arc.lock()实现 java锁
pub static MONITOR_LOCKS: Lazy<Arc<Mutex<HashMap<usize, Arc<JMutex>>>>> = Lazy::new(|| Arc::new(Mutex::new(HashMap::new())));

#[derive(Debug, Default)]
pub struct MONITOR_ENTER {}

impl Instruction for MONITOR_ENTER {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let lock_ref = frame.borrow().get_operand_stack().borrow_mut().pop_ref();    
        if lock_ref.is_none() {
            panic!("java.lang.NullPointerException");
        }
        let thread = frame.borrow().get_thread();
        let key = lock_ref.unwrap() as usize;

        let mut map = MONITOR_LOCKS.lock().unwrap();
        if !map.contains_key(&key) {
            map.insert(key, Arc::new(JMutex::new(key)));
        }
        let lock = map.get(&key).unwrap().clone();
        drop(map);
        
        lock.lock(thread);
    }
}

// 退出同步方法
// Exit monitor for object
#[derive(Debug, Default)]
pub struct MONITOR_EXIT {}

impl Instruction for MONITOR_EXIT {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let lock_ref = frame.borrow().get_operand_stack().borrow_mut().pop_ref();    
        if lock_ref.is_none() {
            panic!("java.lang.NullPointerException");
        }
        let thread = frame.borrow().get_thread();
        let key = lock_ref.unwrap() as usize;

        let map = MONITOR_LOCKS.lock().unwrap();
        if !map.contains_key(&key) {
            return; // 不存在锁直接返回
        }
        let lock = map.get(&key).unwrap().clone();
        drop(map);
        
        lock.unlock(thread);
    }
}

// std::sync::Mutex 实现了 !Send 无法将已上锁的对象存储下来
// 手动实现互斥锁
pub struct JMutex {
    inner: AtomicIsize, // -1 表示线程panic
    key: usize, // 锁在map中的的key
}

unsafe impl Send for JMutex {}
unsafe impl Sync for JMutex {}

impl JMutex {
    pub const fn new(key: usize) -> Self {
        Self { 
            inner: AtomicIsize::new(0),
            key
        }
    }

    pub fn lock(&self, thread: Arc<Mutex<Thread>>) {
        match self.inner.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed) {
            Ok(_) => {
                thread.lock().unwrap().insert_lock(self.key);
                return;
            }, // mutex is now locked!
            Err(_) => (),
        }
        
        // 若当前线程持有此锁, 锁计数加一
        if thread.lock().unwrap().contains_lock(self.key) {
            self.inner.fetch_add(1, Ordering::Relaxed);
        } else {
            // 进入循环尝试获取锁
            self.loop_lock(thread);
        }
    }

    fn loop_lock(&self, thread: Arc<Mutex<Thread>>) {
        loop {
            match self.inner.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed) {
                Ok(_) => {
                    thread.lock().unwrap().insert_lock(self.key);
                    break;
                }, // mutex is now locked!
                Err(_) => continue, // mutex is already locked, try again
            }
        }
    }

    pub fn unlock(&self, thread: Arc<Mutex<Thread>>) {
        let now = self.inner.load(Ordering::Relaxed);
        
        if now == 0 {
            return;
        }
        
        // 锁计数减一，若减为零，当前线程移除持有的锁
        if self.inner.fetch_sub(1, Ordering::Relaxed) == 1 {
            // 线程释放锁
            thread.lock().unwrap().remove_lock(self.key);
        }
    }

    // 释放锁, 用于线程panic或异常释放锁。

    pub fn release_lock(&self) {
        self.inner.store(0, Ordering::Relaxed)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    static mut COUNTER: usize = 0;

    #[test]
    fn test_j_mutex() {
        let mutex = Arc::new(JMutex::new(1));
        let mut threads = Vec::new();
        
        for _ in 0..10 {
            let mutex_ref = mutex.clone();
            let j_thread = Arc::new(Mutex::new(Thread::new_thread(None))); 
            
            threads.push(std::thread::spawn(move || {
                for _ in 0..100_000 {
                    // 上锁 赋值 解锁
                    mutex_ref.lock(j_thread.clone());
                    unsafe { COUNTER += 1; }
                    mutex_ref.unlock(j_thread.clone());
                }
            }));
        }
    
        // Wait for all threads to finish
        for thread in threads {
            thread.join().unwrap();
        }
    
        assert_eq!(unsafe { COUNTER }, 1_000_000);
    }

}